package cn.edu.nuaa.aadl2.generatorC.template

import org.osate.aadl2.DataSubcomponent
import org.osate.aadl2.DataClassifier
import org.osate.aadl2.DataType
import org.osate.aadl2.DataImplementation
import java.util.HashSet
import java.util.Arrays
import cn.edu.nuaa.aadl2.generatorC.utils.Tools
import java.util.List

import static extension cn.edu.nuaa.aadl2.generatorC.template.PropertyTemplate.*

import static extension cn.edu.nuaa.aadl2.generatorC.utils.PropertyUtils.*
import static extension cn.edu.nuaa.aadl2.generatorC.utils.PropertyParser.*
import static extension cn.edu.nuaa.aadl2.generatorC.utils.StringUtils.*
import static extension cn.edu.nuaa.aadl2.generatorC.utils.sortDataType.*
import static extension cn.edu.nuaa.aadl2.generatorC.utils.DataType4C.*;
import org.osate.aadl2.AadlPackage
import org.osate.aadl2.PublicPackageSection
import java.util.ArrayList
import cn.edu.nuaa.aadl2.generatorC.utils.UnionLength
import org.osate.aadl2.Classifier
import java.util.Iterator

class DataTemplate {
	
	private final static String DEFAULT_INCLUDE=
			"			
			#include <wdLib.h>
			#include <msgQlib.h>
			#include <semLib.h>
			#include <pipeDrv.h>
			#include <stdio.h>
			#include <ioLib.h>
			#include <taskLib.h>
			#include <selectLib.h>
			#include <socket.h>
			#include <sockLib.h>
			#include <inetLib.h>
			#include <logLib.h>
			#include <time.h>
			#include <ipProto.h>
			#include <hostLib.h>
			#include <muxLib.h>
			#include <etherMultiLib.h>
			#include <sys/ioctl.h>
			#include <etherLib.h>
			#include <wdLib.h>
			"
	
	private final static String DEFAULT_DEFINE=
	"
			#define bool int
			#define true 1
			#define false 0
			#define TURE true
			#define FLASE false
			#define STRING_SIZE 2
	"
	/*
	 * base types in both c and AADL ,stored by hash set
	 * */
	private final static List<String> basetype=
		Arrays.asList("string", "Integer" , "float" ,"double" , "character")
	private final static HashSet<String> baseTypes = new HashSet<String>(basetype);
	
	def static create(DataSubcomponent subcomponent,String folder)'''
		«Tools.addContent(folder,Template.systemheadfile,subcomponent.template.toString)»
	'''
	
	/**
	 * 
	 * 
	 */
	def static template(DataSubcomponent subcomponent){
		var data=subcomponent.classifier
		switch data{
			DataClassifier : '''
				«data.name.convertNo2Low» «subcomponent.name.convertNo2Low»="«subcomponent.name.convertNo2Low»default"; //DATA 6-24
			'''
			default:'''
			null in DataTemplate.xtend line 40 DataSubcomponent template
			'''
		}
	}
	
	/**
	 * 
	 * 
	 */
	def static dataType(DataClassifier dc,String folder)'''
		«switch dc{
			DataType : '''
				«IF dc.name.equalsIgnoreCase("Integer")»
				«System.out.println("int")»
					int
				«ELSEIF dc.name.equalsIgnoreCase("float")»
					float
				«ELSEIF dc.name.equalsIgnoreCase("long")»
					long
				«ELSEIF dc.name.equalsIgnoreCase("double")»
					double
				«ELSEIF dc.name.equalsIgnoreCase("character")»
					char
				«ELSEIF dc.name.equalsIgnoreCase("string")»
					string
				«ELSE»
					«dc.name.convert»
				«ENDIF»
«««				«IF baseTypes.add(dc.name.toLowerCase)»
«««					«IF dc.dataRepresentation!==null»
«««						«IF dc.dataRepresentation.equalsIgnoreCase("struct")»
«««							«System.out.println("addContent")»
«««							«Tools.addContent(Template.systemheadfile,dc.struct.toString)»
«««						«ENDIF»	
«««						«IF dc.dataRepresentation.equalsIgnoreCase("union")»
«««							«System.out.println("addContent")»
«««							«Tools.addContent(Template.systemheadfile,dc.union.toString)»
«««						«ENDIF»
«««					«ENDIF»
«««				«ENDIF»
			'''
			DataImplementation : '''
				«IF dc.name.equalsIgnoreCase("integer")»
					«System.out.println("int")»
					int
				«ENDIF»
				«IF dc.name.equalsIgnoreCase("float")»
					float
				«ENDIF»
				«IF dc.name.equalsIgnoreCase("double")»
					double
				«ENDIF»
				«IF dc.name.equalsIgnoreCase("character")»
					char
				«ENDIF»
				«IF dc.name.equalsIgnoreCase("string")»
					string
				«ENDIF»
				«IF baseTypes.add(dc.name.toLowerCase)»
					
					«IF dc.dataRepresentation.equalsIgnoreCase("struct")»
					«System.out.println("addContent")»
						«Tools.addContent(folder,Template.systemheadfile,dc.struct(folder).toString)»
						«System.out.println(dc.struct(folder).toString+"s")»
					«ENDIF»	
					«IF dc.dataRepresentation.equalsIgnoreCase("union")»
					«System.out.println("addContent")»
						«Tools.addContent(folder,Template.systemheadfile,dc.union(folder).toString)»
						«System.out.println(dc.union(folder).toString+"s")»
					«ENDIF»	
				«ENDIF»
			'''
		}»
	'''
	/**
	 * 
	 */
	def static struct(DataClassifier dc,String folder){
		switch dc{
			DataType : '''				
				typedef struct
				{	
					«data(dc.baseTypes0,dc.elementNames,folder)»		
				}«dc.name.convertNo2Low»;
			'''
			DataImplementation : '''
				typedef struct
				{
					«data(dc.baseTypes0,dc.elementNames,folder)»		
				}«dc.name.convertNo2Low»;
			'''
		}
	}
	/**
	 * 
	 */
	def static union(DataClassifier dc,String folder){
		switch dc{
			DataType: '''
				typedef union «dc.name.convertNo2Low»
				{
					«data(dc.baseTypes0,dc.elementNames,folder)»		
				}«dc.name.convertNo2Low»;
			'''
			DataImplementation : '''
				typedef union «dc.name.convertNo2Low»
				{
					«data(dc.baseTypes0,dc.elementNames,folder)»		
				}«dc.name.convertNo2Low»;
			'''
		}
	}
	
	
	/**
	 * 
	 * 
	 */
	def static data(List<DataClassifier> datas,List<String> vars,String folder){
		var result=""
		var i=0
		var size=datas.size
		for(i=0;i<size;i++){
			result=result+datas.get(i).dataType(folder).toString.replaceAll("\r|\n", "")+ " "+vars.get(i)+";\n"
		}
		return result
	}
	
	
	
	
	/**
	 * 处理publicSection中的所有数据实现类型
	 * @param aadlPackage aadl包
	 */

	
	def static genDataType(AadlPackage aadlPackage){
		var dataImpls = aadlPackage.publicSection.allDataImplementation
		if(dataImpls.size > 0){
			return dataImpls.dealDataComponent.toString()
		}
	}
	/**
	 * 处理系统实现下的数据子组件
	 * @param folder 系统目录
	 * @param systemName 系统名称
	 * @param dataSubcomponents 数据子组件列表
	 */
	def static genSystemDataSubcomponent(String folder, String systemName, List<DataSubcomponent> dataSubcomponents){
		Tools.createFile(folder,systemName.convert+"_data.h",systemDataSubcomponent(systemName,dataSubcomponents).toString)
	}
	
	def static systemDataSubcomponent(String systemName, List<DataSubcomponent> dataSubcomponents)'''
			«FOR DataSubcomponent dataSubcomponent : dataSubcomponents»
				«dataSubcomponent.template»
			«ENDFOR»
	'''	
	
	/**
	 * 处理进程实现下的数据子组件
	 * @param dataSubcomponents 数据子组件列表
	 */
	def static genProcessDataSubcomponent(List<DataSubcomponent> dataSubcomponents)'''
		«FOR dataSubcomponent : dataSubcomponents»
			«dataSubcomponent.template»
		«ENDFOR»
	'''	
	
	
	
	
	

	/**
	 * 
	 * dataType数据字典的生成,生成一个独立的dataType头文件,并自动包含进顶层系统的头文件中
	 * TODO 对DataImplementation的解析独立地实现,应该抽成公共函数,供所有其它过程中生成data组件内容使用
	 * @param 数据字典中的所有数据实现组件
	 */
	def static dealDataComponent(List<DataImplementation> datas)'''
		«IF datas!=null»
			«DEFAULT_INCLUDE»
			«DEFAULT_DEFINE»
	«««		生成的data struct或者union、array ,他们之间存在相互引用,相互应用就要考虑先后的问题 ,这里对所有数据构建进行拓扑排序
			«var ans=datas.sort»
			«FOR data : ans»
				«data.data2C»
			«ENDFOR»
		«ELSE»
			   /**********************/
			   /* 数据字典空
			   /**********************/
		«ENDIF»
	'''
	
	
	/**
	 * 处理每个data的属性集,判断是哪种类型
	 * TODO 当前默认处理所有data是Union,然后如果有特定属性就按照特定规则生成; 正确的方式应该是,解析每个data的属性,并按照指定的数据类型特其它相关属性生成 如果没有属性则报错
	 * 
	 */
	def static data2C(DataImplementation data)'''
	«IF data.allPropertyAssociations.size>1»
«««	 TODO data2C swtich
		«switch data.dataRepresentation{
			case "Struct":'''
			typedef struct «data.name.convertNo2Low»_struct{
				«FOR code:data.structORUnionStrings»
					«code»
				«ENDFOR»
			} «data.name.convertNo2Low»;
			'''
			case "Union":'''
			//"Union" TODO:asdfasd
			«data.structORUnionStrings»		
			'''
			default:'''
			«data.dataRepresentation» «data.name.convertNo2Low»[«data.myDimension»];  
			'''
		}»
	
	«ELSE»
		«data.data2Union»
	«ENDIF»	

	'''

		
	/**
	 * 
	 */
	def static data2Union(DataImplementation data)'''
		«««		为每个生成数据构建加个ID? 这一步的添加 是为了防止生成的头文件结构体为空报错(结构体不允许为空)
		«var i=0»
		«var LENGTH=new UnionLength()»
		/**************************/
		/*                         
		/*  Union{task}  «data.name»    
		/**************************/
		typedef union «data.name.convertNo2Low»_union
		{
			struct{
			int STRUCT_ID : «i++»;
			«FOR subData : data.ownedDataSubcomponents»
				«IF subData!=null»
«««					«subData.dealDataType.toString.clearspace» «subData.name.convert»;
					«val type=subData.dealData()»
					«IF type.isArray»
						«type.name» «subData.name»[«type.size»]; 
						«LENGTH.plus(type.value*type.size)»
					«ELSE»
						«type.name» «subData.name»; 
						«LENGTH.plus(type.value)»
					«ENDIF»
					«LENGTH.plus(type.value)»
				«ELSE»
					bool «subData.name.convertNo2Low»; 
					«LENGTH.plus(1)»
				«ENDIF»
			«ENDFOR»
			}STRUCT_BITS;
			char data[«LENGTH.value»];   // TODO
		}«data.name.convertNo2Low»; 	
	'''
	
	// 实在不建议使用array 这个语义有点怪 我认为我们生成的模型没有引用这种数据类型的能力
	// ...在AADL中的Array是个不限制类型的数组,意味着里面可以存各种类型,只是大小确定而已,c中没有这种容器 我在这里就把AADL的Array也解析成Struct
	// 这个函数处理的是那些DataRepresentation 是基础类型的,且纬度不为零的元素数组
	// 进来前就会解析好纬度 所以这个函数可能直接抛弃
	def static data2Array()''''''
	// 这里处理生成Struct
	// 分别需要获得
	// Data_Model::Base_Type (list)
	// Data_Model::Dimension (list)
	// Data_Model::Element_Names (list)
	// 这三个list是一一对应的
	
	
	def static data2Struct(List<String> baseType,List<String> dimension,List<String> elementNames){
		if(baseType.size==dimension.size && baseType.size == elementNames.size){
			var buf=""
			var type=baseType.iterator;
			var names=elementNames.iterator
			var dimensions=dimension.iterator
			while (type.hasNext) {
				buf+=type.next + " " +names.next+"["+dimensions.next+"];\n"
			}
			return buf;
		}
		else
			return "// Base_Type.size==Dimension.size && Base_Type.size == Element_Names.size =>FALSE" ; 
	}
	
	
	def static data2Basic()''''''
	

	
	def static dealData(DataSubcomponent dataSubcomponent){
		var dataType=dataSubcomponent.dataSubcomponentType.name.dealDataType
		var dimensions=dataSubcomponent.arrayDimensions
		if(dimensions.size!=0)
			dataType.size = dimensions.get(0).size.size
		return dataType
	}
	
	
	def static isArray(){
		
	}
	
	def static dealDataType(String s){
		switch s{
			case "Float":return Float
			case "Integer":return Integer
			case "Boolean":return Boolean
			case "Character":return Character
			case "String":return String
			default:return NULL
		}
	}
	
	/*
	 * 获得publicSection下的所有Data Implementation对象
	 * @param publicSection 
	 * @return List<Classifier>
	 */
	def static getAllDataImplementation(PublicPackageSection publicSection){
		var result = new ArrayList<DataImplementation>();
		for(classifier : publicSection.ownedClassifiers){
			switch classifier{
				DataImplementation:	
					result.add(classifier)
				default:
					println("DataTemplate 288 ,default 4 " +  classifier)
				
			};
		}
		return result
	}
	
	
	
}

